/*
** Test Math and Fixed Point by Neil C. Obremski              [ Magenta's Maze ]
** 2017 Gibdon Moon Productions                   [ http://magsmaze.gibdon.com ]
**
** This is free and unencumbered software released into the public domain.
**
** Anyone is free to copy, modify, publish, use, compile, sell, or
** distribute this software, either in source code form or as a compiled
** binary, for any purpose, commercial or non-commercial, and by any
** means.
**
** In jurisdictions that recognize copyright laws, the author or authors
** of this software dedicate any and all copyright interest in the
** software to the public domain. We make this dedication for the benefit
** of the public at large and to the detriment of our heirs and
** successors. We intend this dedication to be an overt act of
** relinquishment in perpetuity of all present and future rights to this
** software under copyright law.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
** IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
** OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
** OTHER DEALINGS IN THE SOFTWARE.
**
** Tested w/ DOSBox 0.74, Microsoft C 5.10
*/
#include <math.h>
#include <stdio.h>
#include <stdlib.h>

#include "mag-cga.h"
#include "mag-math.h"
#include "mag-3d.h"

void autofx(void);
void autoroots(void);
void printfx(char *);
void testfx(void);

int main(int argc, char *argv[])
{
	if (argc < 2) {
		unsigned int counter = 0;
		int i = 0;
		for (counter -= 149; counter > 149; counter -= 149) {
			printf("%d: %u > 149\n", i++, counter);
		}
		autofx();
		autoroots();
	} else if (!stricmp(argv[1], "roots")) {
		int i = 2;
		struct term terms[MAX_TERM];
		memset(terms, 0, sizeof(terms));
		for ( ; i < argc; i++) {
			addroot(terms, atoi(argv[i]));
		}
		puts(polynomial(terms));
	} else if (!stricmp(argv[1], "fx")) {
		testfx();
	} else if (!stricmp(argv[1], "sin")) {
		printfx("SIN");
	} else if (!stricmp(argv[1], "cos")) {
		printfx("COS");
	} else if (!stricmp(argv[1], "90")) {
		int deg = 0;
		for ( ; deg < 360; deg += 90) {
			printf("%3d%c = %+d,%+d\n", deg, DEGCHAR,
				MUL_SIN_DEG(1,deg), MUL_COS_DEG(1,deg));
		}
	}

	return 0;
}

void autofx(void)
{
	int x = 10;
	long fx = INT_FX(x);

	printf("X = %d (0x%lx) + 0.5 ...\n", (int)ROUND_FX(fx), fx);
	fx += FX_0_5;
	printf("X = %d (0x%lx) + 2.5 ...\n", (int)ROUND_FX(fx), fx);
	fx += FX_2_5;
	printf("X = %d (0x%lx)\n", (int)ROUND_FX(fx), fx);
}

void autoroots(void)
{
	printf("ROOTS [-3,7,4] = %s\n",
		polynomial(roots(3, -3, 7, 4)));

	printf("ROOTS [4,-3,7] = %s\n",
		polynomial(roots(3, 4, -3, 7)));

	printf("ROOTS [1,-1,-4] = %s\n",
		polynomial(roots(3, 1, -1, -4)));

	printf("ROOTS [1,1] = %s\n",
		polynomial(roots(2, 1, 1)));

	printf("ROOTS [3,3] = %s\n",
		polynomial(roots(2, 3, 3)));

	printf("ROOTS [3,3,3] = %s\n",
		polynomial(roots(3, 3, 3, 3)));

}

/* output 15-bit (-16384 to +16384 fractional range) for a math function */
void printfx(char *func)
{
	double rad, n;
	int deg, i;
	int is_sin = 0, is_cos = 0, is_rad = 0;

	if (0 == stricmp("SIN", func)) {
		is_sin = 1;
	} else if (0 == stricmp("COS", func)) {
		is_cos = 1;
	} else if (0 == stricmp("RAD", func)) {
		is_rad = 1;
	}

	printf("int %s_FX[] = {\n\t", func);

	for (deg = 0; deg < 360; deg++) {
		rad = DEG2RAD((double)deg);

		if (is_sin) {
			n = sin(rad);
		} else if (is_cos) {
			n = cos(rad);
		} else if (is_rad) {
			n = rad;
		}

		i = (int)ceil(n * 16384.0);

		printf("%d", i);

		if (deg < 359) {
			putchar(',');
		}

		if (0 == (1+deg) % 8) {
			if (deg < 359) {
				printf("\n\t");
			} else {
				printf("\n");
			}
		} else {
			putchar(' ');
		}
	}

	printf("};\n");
}

/* interactive command-line test for fixed point calculations */
void testfx(void)
{
	int x, y, deg;
	double nx, ny, nr;

	for (;;) {
		printf("Input X: ");
		scanf("%d", &x);
		if (0 == x) {
			break;
		}
		printf("Input Y: ");
		scanf("%d", &y);
		if (0 == y) {
			break;
		}
		printf("Input Rotation (degrees): ");
		scanf("%d", &deg);

		printf("Rotating (%d,%d) by %d degrees ...\n", x, y, deg);

		nr = DEG2RAD(deg);
		nx = y*sin(nr) + x*cos(nr);
		ny = y*cos(nr) - x*sin(nr);
		printf("Float: %.2f, %.2f (%.4f sin, %.4f cos, %.4f radians)\n",
			nx, ny, sin(nr), cos(nr), nr);

		rotatefx(&x, &y, deg);
		printf("  Int: %d, %d (0x%x sin, 0x%x cos)\n",
			x, y, SIN_FX[deg], COS_FX[deg]);
		printf("\n");
	}
}
